require 'gosu'
require 'utils'
require 'zindex'
require 'ruby_stone'


class Player
  SIZE = 50
  MAX_LIVES=3
  JUMP_SIZE=-20 #must be negative!
  JUMP_STEP=0.5 #amount of vertical velocity per step
  STEPS=3 #steps to move each update
  
  attr_reader :x, :y, :score, :standing, :walk1, :walk2, :jump, :killed_img
  
  def initialize(window)    
    @window=window
    @dir = :left
    @vy = 0 # Vertical velocity    
    # Load all animation frames
    @standing, @walk1, @walk2, @jump, @killed_img =
      *Image.load_tiles(window, "#{cur_dir}/graphics/southpark_sprite.png", SIZE, SIZE, false)    
    @cur_image = @standing    
    @jump_sound= Gosu::Sample.new(window, "#{cur_dir}/sound/swoosh.wav")
    @kill_sound= Gosu::Sample.new(window, "#{cur_dir}/sound/wawawawa.wav")
    @player_font = Gosu::Font.new(window, "Arial Black", 60)
    @score_font = Gosu::Font.new(window, Gosu::default_font_name, 10)
    @score_sound= Gosu::Sample.new(window, "#{cur_dir}/sound/yodel.wav")
    @score=0
    @lives=MAX_LIVES
    @life_img=Image.new(window, "#{cur_dir}/graphics/life_icon.png", false)
    @killed=false
  end
  
  def update(move_x)
    return if @killed    
    
    if (move_x == 0)
      @cur_image = @standing
    else
      @cur_image = (milliseconds / 175 % 2 == 0) ? @walk1 : @walk2
    end
    if (@vy < 0)
      @cur_image = @jump
    end
    
    vpadding=(SIZE-5)*-1
    # Directional walking, horizontal movement
    if move_x > 0 then      
      @dir = :right    
      STEPS.times { if @window.map.would_fit(@x,@y,SIZE, 0, 0, vpadding) then @x += 1 end } #I use a padding of SIZE - 5 to improve collisions detection
    elsif move_x < 0 then
      @dir = :left      
      STEPS.times { if @window.map.would_fit(@x,@y,0, 0, 0, vpadding) then @x -= 1 end }
    end
    
    # By adding 1 each frame, and (ideally) adding vy to y, the player's
    # jumping curve will be the parabole we want it to be.
    @vy += JUMP_STEP    
    if @vy > 0 then
      @vy.to_i.times { if @window.map.would_fit(@x,@y,SIZE/2, 1, 0, vpadding) then @y += JUMP_STEP else @vy = 0 end }
    end
    if @vy < 0 then
      (-@vy).to_i.times { if @window.map.would_fit(@x,@y,SIZE/2, -1, 0, vpadding) then @y -= JUMP_STEP else @vy = 0 end }
    end
  end
  
  def draw(screen_x, screen_y)      
    if @killed
      @cur_image=@killed_img            
      
      @player_font.shadow_text("EPIC FAIL!!", 50, 50, Zindex::TEXT, 1.5, 1.25, 0xEEFBCD2C)
      @player_font.draw("YOU LOST A LIFE!!", 10, 150, Zindex::TEXT, 1.25, 1.0, 0xFFFF0000)
      @player_font.draw("<SPACE> TO CONTINUE", 30, 230, Zindex::TEXT, 1.0, 1.0, 0xFFFF7900)
    end
    @cur_image.draw(@x - screen_x, @y - screen_y - (SIZE-1), Zindex::PLAYER)
    draw_score
  end
  
  def draw_score
    @lives.times do |i|
      @life_img.draw( 10 +  30 * i,  20,  Zindex::SCORE,0.5,0.5)      
    end
    @score_font.draw("%06d" % @score, 10, 0,  Zindex::TEXT, 3.0, 2.0, 0xCCffff00)
  end
  
  def kill    
    @window.set_state(:wait)
    @killed=true    
    @lives -= 1
    @vy=0
    if @lives <= 0
      @window.set_game_over
    else
      @kill_sound.safe_play(1)
    end 
  end
  
  def reset(reset_lives=false)
    @map = @window.map
    EvilDuke.load_from_map(@window)
    @lives=MAX_LIVES and @score=0 if reset_lives
    @killed=false
    @x=(@map.player_x + 1 ) * SIZE - 1
    @y=(@map.player_y + 1) * SIZE - 1
  end
  
  def try_to_jump
    if @map.solid?(@x, @y + 1) then      
      @jump_sound.safe_play(0.5)
      @vy = JUMP_SIZE 
    end
  end
  
  def collect_gems(gems)    
    gems.reject! do |c|      
      if (c.x - @x).abs < SIZE and (c.y - @y).abs < SIZE
        @score_sound.safe_play
        @score += RubyStone::SCORE
        true
      else
        false
      end
    end
    if gems.empty?
      @window.level_up
    end
  end
end
